<script setup lang="ts">
import { computed, nextTick, ref, shallowRef, watch } from 'vue';
import { $t } from '@/locales';
import {
  fetchGetAllPages,
  fetchGetMenuTree,
  fetchGetRoleMenuPermissions,
  fetchUpdateRoleMenuPermissions
} from '@/service/api';

defineOptions({
  name: 'MenuAuthModal'
});

interface Props {
  /** the roleId */
  roleId: number;
}

interface Emits {
  (e: 'submitted'): void;
}

const props = defineProps<Props>();
const emit = defineEmits<Emits>();

const visible = defineModel<boolean>('visible', {
  default: false
});

function closeModal() {
  visible.value = false;
}

const title = computed(() => $t('common.edit') + $t('page.manage.role.menuAuth'));

const home = shallowRef('');

async function getHome() {
  home.value = 'home';
}

async function updateHome(val: string) {
  // request

  home.value = val;
}

const pages = shallowRef<string[]>([]);

async function getPages() {
  try {
    const { error, data } = await fetchGetAllPages();

    if (!error && data) {
      pages.value = data;
    } else {
      pages.value = [];
    }
  } catch (err) {
    pages.value = [];
  }
}

const pageSelectOptions = computed(() => {
  const opts: CommonType.Option[] = pages.value.map(page => ({
    label: page,
    value: page
  }));

  return opts;
});

const tree = shallowRef<Api.SystemManage.MenuTree[]>([]);

async function getTree() {
  try {
    const { error, data } = await fetchGetMenuTree();

    if (!error && data) {
      tree.value = Array.isArray(data) ? data : [];
    } else {
      tree.value = [];
      const errorMsg = error?.message || $t('page.manage.role.error.getMenuTreeFailed');
      window.$message?.error?.(errorMsg);
    }
  } catch (err: any) {
    tree.value = [];
    const errorMsg = err?.message || err?.response?.data?.msg || $t('page.manage.role.error.getMenuTreeError');
    window.$message?.error?.(errorMsg);
  }
}

const checks = ref<number[]>([]);
const checkedKeys = ref<number[]>([]); // 使用数字数组，与菜单ID类型保持一致
const indeterminateKeys = ref<number[]>([]);
const loading = ref(false);
const treeKey = ref(0); // 用于强制刷新树组件

// 检查菜单节点是否存在于菜单树中
function isValidMenuId(menuId: number): boolean {
  function findInTree(menuList: Api.SystemManage.MenuTree[]): boolean {
    return menuList.some(menu => {
      if (menu.id === menuId) {
        return true;
      }
      if (menu.children && menu.children.length > 0) {
        return findInTree(menu.children);
      }
      return false;
    });
  }

  return findInTree(tree.value);
}

// 过滤无效的菜单ID
function filterValidMenuIds(menuIds: number[]): number[] {
  return menuIds.filter(id => isValidMenuId(id));
}

async function getChecks() {
  try {
    loading.value = true;

    // 验证roleId是否有效
    if (!props.roleId || props.roleId <= 0) {
      window.$message?.error?.($t('page.manage.role.error.invalidRoleId'));
      return;
    }

    const { error, data } = await fetchGetRoleMenuPermissions(props.roleId);
    if (!error && data) {
      const rawMenuIds = Array.isArray(data) ? data.map(id => Number(id)).filter(id => !Number.isNaN(id)) : [];
      const validMenuIds = filterValidMenuIds(rawMenuIds);

      checks.value = validMenuIds;
      checkedKeys.value = [...validMenuIds];
      indeterminateKeys.value = [];

      await nextTick();

      if (validMenuIds.length > 0) {
        setTimeout(() => {
          if (checkedKeys.value.length === 0) {
            checkedKeys.value = [...validMenuIds];
            treeKey.value++;
          }
        }, 100);
      }
    } else {
      const errorMsg = error?.message || $t('page.manage.role.error.getRoleMenuPermissionsFailed');
      window.$message?.error?.(errorMsg);
      checks.value = [];
      checkedKeys.value = [];
      indeterminateKeys.value = [];
    }
  } catch (err: any) {
    const errorMsg =
      err?.message || err?.response?.data?.msg || $t('page.manage.role.error.getRoleMenuPermissionsError');
    window.$message?.error?.(errorMsg);
    checks.value = [];
    checkedKeys.value = [];
    indeterminateKeys.value = [];
  } finally {
    loading.value = false;
  }
}

// 获取需要提交给后端的菜单ID
function getAllSelectedMenuIds(): number[] {
  return checkedKeys.value.map(id => Number(id)).filter(id => !Number.isNaN(id));
}

// eslint-disable-next-line complexity
async function handleSubmit() {
  try {
    loading.value = true;

    // 验证roleId是否有效
    if (!props.roleId || props.roleId <= 0) {
      window.$message?.error?.($t('page.manage.role.error.invalidRoleId'));
      return;
    }

    const allSelectedIds = getAllSelectedMenuIds();

    // 验证菜单ID数组
    if (!Array.isArray(allSelectedIds)) {
      window.$message?.error?.('菜单权限数据无效');
      return;
    }

    const { error } = await fetchUpdateRoleMenuPermissions(props.roleId, allSelectedIds);

    if (!error) {
      window.$message?.success?.($t('common.modifySuccess'));
      emit('submitted');
      closeModal();
    } else {
      const errorMsg = error?.message || $t('common.operationFailed');
      window.$message?.error?.(errorMsg);
    }
  } catch (err: any) {
    const errorMsg = err?.message || err?.response?.data?.msg || $t('common.operationFailed');
    window.$message?.error?.(errorMsg);
  } finally {
    loading.value = false;
  }
}

async function init() {
  checks.value = [];
  checkedKeys.value = [];
  indeterminateKeys.value = [];

  try {
    await Promise.all([getHome(), getPages(), getTree()]);

    if (tree.value.length > 0) {
      await getChecks();
    }

    await nextTick();
  } catch (error) {
    window.$message?.error?.('初始化菜单权限失败');
  }
}

watch(visible, async val => {
  if (val) {
    await init();
  }
});

// 监听 checkedKeys 变化，同步更新 checks
watch(
  checkedKeys,
  newKeys => {
    const numericValues = newKeys.map(id => Number(id)).filter(id => !isNaN(id));
    checks.value = numericValues;
  },
  { deep: true }
);

// 获取所有菜单ID（包括子菜单）
function getAllMenuIds(): number[] {
  const allIds: number[] = [];

  function collectIds(menuList: Api.SystemManage.MenuTree[]) {
    menuList.forEach(menu => {
      allIds.push(menu.id);
      if (menu.children && menu.children.length > 0) {
        collectIds(menu.children);
      }
    });
  }

  collectIds(tree.value);
  return allIds;
}

// 全选
function selectAll() {
  const allMenuIds = getAllMenuIds();
  checks.value = [...allMenuIds];
  checkedKeys.value = [...allMenuIds];
  indeterminateKeys.value = [];
}

// 反选
function invertSelection() {
  const allMenuIds = getAllMenuIds();
  const currentSelected = new Set(checks.value);
  const newSelected: number[] = [];

  allMenuIds.forEach(id => {
    if (!currentSelected.has(id)) {
      newSelected.push(id);
    }
  });

  checks.value = newSelected;
  checkedKeys.value = [...newSelected];
  indeterminateKeys.value = [];
}

// 清空
function clearAll() {
  checks.value = [];
  checkedKeys.value = [];
  indeterminateKeys.value = [];
}
</script>

<template>
  <NModal v-model:show="visible" :title="title" preset="card" class="w-480px">
    <div class="flex-y-center gap-16px pb-12px">
      <div>{{ $t('page.manage.menu.home') }}</div>
      <NSelect :value="home" :options="pageSelectOptions" size="small" class="w-160px" @update:value="updateHome" />
    </div>

    <!-- 操作按钮 -->
    <div class="flex gap-8px pb-12px">
      <NButton size="small" :disabled="loading" @click="selectAll">
        {{ $t('common.selectAll') }}
      </NButton>
      <NButton size="small" :disabled="loading" @click="clearAll">
        {{ $t('common.clear') }}
      </NButton>
      <NButton size="small" :disabled="loading" @click="invertSelection">
        {{ $t('common.invert') }}
      </NButton>
    </div>

    <NTree
      :key="treeKey"
      v-model:checked-keys="checkedKeys"
      v-model:indeterminate-keys="indeterminateKeys"
      :data="tree"
      key-field="id"
      label-field="menuName"
      children-field="children"
      checkable
      cascade
      expand-on-click
      block-line
      default-expand-all
      class="h-280px"
    />
    <template #footer>
      <NSpace justify="end">
        <NButton size="small" class="mt-16px" :disabled="loading" @click="closeModal">
          {{ $t('common.cancel') }}
        </NButton>
        <NButton type="primary" size="small" class="mt-16px" :loading="loading" @click="handleSubmit">
          {{ $t('common.confirm') }}
        </NButton>
      </NSpace>
    </template>
  </NModal>
</template>

<style scoped></style>
